package com.eryos.test.springsecurity.login;

/**
 * Project :  SpringSecuritySimple
 * Author :   Olivier Combe
 * URL :      http://eryos-tech.blogspot.com/
 *
 * Copyright (C) 2011 - Olivier Combe 
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 *
 */

import com.eryos.test.springsecurity.login.service.LoginService;
import com.eryos.test.springsecurity.login.service.LoginServiceAsync;
import com.eryos.test.springsecurity.shared.SimpleUser;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.AnchorElement;
import com.google.gwt.dom.client.ButtonElement;
import com.google.gwt.dom.client.InputElement;
import com.google.gwt.dom.client.Style.Visibility;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.History;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.Button;

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class Login implements EntryPoint, ValueChangeHandler<String> {

	/* ******************* Service(s) ******************* */
	private final LoginServiceAsync loginService = GWT.create(LoginService.class);
	
	/* ******************* Tokens & Steps ******************* */
	private static final String LOGIN 							= "";
	private static final String REQUEST 						= "Register";
	private static final String LOGIN_FAILURE 					= "loginFailure";
	private static final String SESSION_TIMEOUT 				= "timeout";	
	private static final String ACCESS_DENIED 					= "accessDenied";	
	private static final String LOGOUT 							= "logout";
	
	/* ******************* DOM Ids ******************* */
	private static final String DOM_REGISTER_DIV 				= "registerDiv";
	private static final String DOM_LOGIN_DIV 	 				= "loginDiv";	
	private static final String DOM_REGISTER_USERNAME 	 		= "username";
	private static final String DOM_REGISTER_PASSWORD 	 		= "password_1";
	private static final String DOM_REGISTER_PASSWORD_CONFIRM 	= "password_2";
	private static final String DOM_REGISTER_MAIL 	 			= "mail";
	private static final String DOM_REGISTER_LINK 	 			= "registerLink";
	private static final String DOM_REGISTER_BUTTON 	 		= "registerButton";
	private static final String DOM_SPAN_MESSAGE 	 			= "message";

	/* ******************* HTML Form Elements******************* */
	private InputElement  registerUsernameField;
	private InputElement  registerPasswordField;
	private InputElement  registerPasswordConfirmField;
	private InputElement  registerMailField;
	private AnchorElement registerLink;
	private ButtonElement registerButtonElt;
	
	/* ******************* Registration values ******************* */
	private String username;
	private String password;
	private String confirmPassword;
	private String mail;


	/**
	 * Method called when Login.jsp is displayed
	 */
	public void onModuleLoad() {
		/* Retrieve Register Fields */
		parseDOMFields();

		/* Add history handler */
		History.addValueChangeHandler(this);

		/* Show the appropriate view */
		History.fireCurrentHistoryState();
	}

	/**
	 * Method called when the token change in the URL bar ( used for history browsing )
	 * @param event  
	 */
	@Override
	public void onValueChange(ValueChangeEvent<String> event) {
		String token = event.getValue();
		System.out.println(token);
		
		if (token != null ) {
			
			if (token.equals(LOGIN)) {
				showLoginPart();
			} else if (REQUEST.equals(token)) {
				showRegisterPart();
			}else if (LOGIN_FAILURE.equals(token)) {
				showMessage("Autenthication failure ... please retry");
				showLoginPart();								
			}else if (SESSION_TIMEOUT.equals(token)) {
				showMessage("Session Timeout occurs ... please retry");
				showLoginPart();				
			}else if (LOGOUT.equals(token)) {
				showMessage("You are now logged out. Good bye");
				showLoginPart();				
			}else if (ACCESS_DENIED.equals(token)) {
				showMessage("You are allowed to access this page");
				showLoginPart();				
			}else {
				showMessage("Unknown token ... ");
				showLoginPart();
			}			
		}
	}

	/**
	 * Method used to show the Login part of the page and hide the Register part
	 */
	private void showLoginPart(){
		DOM.getElementById(DOM_REGISTER_DIV).getStyle().setVisibility(Visibility.HIDDEN);
		DOM.getElementById(DOM_LOGIN_DIV).getStyle().setVisibility(Visibility.VISIBLE);

		/* Add Anchor to show the Register part */
		Anchor a = Anchor.wrap(registerLink);		
		a.addClickHandler(new ClickHandler(){
			@Override
			public void onClick(ClickEvent event) {				
				History.newItem("Register");		
			}
		});
	}

	/**
	 * Method used to show the Register part of the page and hide the Login part
	 */
	private void showRegisterPart(){
		DOM.getElementById(DOM_LOGIN_DIV).getStyle().setVisibility(Visibility.HIDDEN);
		DOM.getElementById(DOM_REGISTER_DIV).getStyle().setVisibility(Visibility.VISIBLE);

		Button registerButton = Button.wrap(registerButtonElt);
		
		/* Handle Register button */
		registerButton.addClickHandler(new ClickHandler(){

			@Override
			public void onClick(ClickEvent event) {

				/* Retrieve data from HTML Form elements */
				parseFormValues();
				
				/* Check if values are OK */
				if ( checkFormValidity() ){
					
					SimpleUser user = new SimpleUser();
					user.setUsername(username);
					user.setPassword(password);
					user.setEmail(mail);

					/* Add the new User in the DataStore */
					loginService.registerNewUser(user, new AsyncCallback<Boolean>(){
						@Override
						public void onFailure(Throwable caught) {
							showMessage("Registration failled : "+caught.getMessage());
							caught.printStackTrace();
						}

						@Override
						public void onSuccess(Boolean result) {
							showMessage("Your account is created, you can now login...");
							showLoginPart();
						}
					});
				}
			}
		});
	}	
		
	/**
	 * Method used to check if the form is well filled or not
	 * @return well formed or not
	 */
	private boolean checkFormValidity(){
		
		if ( username != null && username.length() > 3 ){
			if (password.equalsIgnoreCase(confirmPassword)){				
				if ( password != null && password.length() >= 6 ){									
					if(mail !=null && mail.length() > 6 && mail.contains("@")){						
						return true;						
					}else{
						showMessage("Email is not valid !!");
						return false;
					}					
				}else{
					showMessage("Password is not valid !!");
					return false;
				}
			}else {		
				showMessage("Password is not the same in both fields !!");
				return false;
			}
		}else {
			showMessage("Username is not valid !!");
			return false;
		}
	}
	
	/**
	 * Show a message in the 'span' element of the Login.jsp page
	 * @param msg
	 */
	private void showMessage(String msg){
		DOM.getElementById(DOM_SPAN_MESSAGE).setInnerText(msg);
	}
	
	/**
	 * Retrieve fields from DOM's Ids
	 */
	private void parseDOMFields(){	
		registerUsernameField 			= InputElement.as(DOM.getElementById(DOM_REGISTER_USERNAME));
		registerPasswordField 			= InputElement.as(DOM.getElementById(DOM_REGISTER_PASSWORD));
		registerPasswordConfirmField 	= InputElement.as(DOM.getElementById(DOM_REGISTER_PASSWORD_CONFIRM));
		registerMailField 				= InputElement.as(DOM.getElementById(DOM_REGISTER_MAIL));
		registerLink 					= AnchorElement.as(DOM.getElementById(DOM_REGISTER_LINK));
		registerButtonElt 				= ButtonElement.as(DOM.getElementById(DOM_REGISTER_BUTTON));
	}

	/**
	 * Retrieve content of DOM fields
	 */
	private void parseFormValues(){
		
		username = registerUsernameField.getValue();
		password = registerPasswordField.getValue();
		confirmPassword = registerPasswordConfirmField.getValue();
		mail = registerMailField.getValue();
	}

}
